package com.librariy.view;
import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.hardware.Camera;
import android.os.AsyncTask;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.Toast;
import java.io.ByteArrayOutputStream;
@SuppressWarnings({"deprecation","StaticFieldLeak"})
public class FaceCameraView extends FrameLayout implements SurfaceHolder.Callback,Camera.FaceDetectionListener{
    private static final String TAG = "FaceCameraView";
    private CameraWrap mCameraWrap=new CameraWrap();
    private RectF clipRect = new RectF(0, 0, 0, 0);
    private RectF viewRect = new RectF(0, 0, 0, 0);
    private RectF faceRegion=new RectF(0,0,0,0);
    private EventListener mListener;
    private int cameraId=CameraWrap.CAMERA_FACING_FRONT;
    private SurfaceView mSurfaceView;
    public FaceCameraView(Context mContext) {
        super(mContext);
        this.initialize(mContext);
    }
    public FaceCameraView(Context mContext, AttributeSet attrs) {
        super(mContext, attrs, 0);
        this.initialize(mContext);
    }
    public FaceCameraView(Context mContext, AttributeSet attrs, int defStyleAttr) {
        super(mContext, attrs, defStyleAttr);
        this.initialize(mContext);
    }
    private void initialize(Context mContext) {
        this.mSurfaceView=new SurfaceView(mContext);
        this.mSurfaceView.getHolder().setKeepScreenOn(true);
        this.mSurfaceView.getHolder().addCallback(this);
        super.addView(mSurfaceView,new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        super.addView(new Sharp(mContext),new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
    }
    @Override
    public void onFaceDetection(Camera.Face[] faces, Camera camera) {
        if(faces==null) return;
        if(!faceRegion.isEmpty()) {
            return;
        }
        Matrix matrix=mCameraWrap.faceMapMatrix(viewRect.width(),viewRect.height());
        for(Camera.Face face:faces){
            final RectF r=new RectF(face.rect);
            matrix.mapRect(r);
            if(!clipRect.contains(r)){
                //判断人脸是否在取景窗内
                continue;
            }
            r.union(clipRect);
            faceRegion.set(r);
            takePicture(0);
            break;
        }
    }
    public void startPreview() {
        mCameraWrap.initCameraParameters(getDisplay());
        mCameraWrap.setFaceDetectionListener(this);
        mCameraWrap.startPreview(true);
        faceRegion.setEmpty();
    }
    public void stopPreview() {
        mCameraWrap.stopPreview(true);
        mCameraWrap.setFaceDetectionListener(null);
    }
    public void takePicture(final float degrees) {
        mCameraWrap.takePicture(true,new Camera.PictureCallback(){
            @Override
            public void onPictureTaken(byte[] data, Camera camera) {
                stopPreview();
                processImage(data,degrees);
            }
        });
    }
    public void processImage(final byte[] jpeg,final float degrees){
        AsyncTask<Void,Void, byte[]> task=new AsyncTask<Void,Void,byte[]>(){
            private ProgressDialog progressDialog;
            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                progressDialog = ProgressDialog.show(getContext(),"","正在处理图片...");
                mCameraWrap.stopPreview(false);
            }
            @Override
            protected byte[] doInBackground(Void... voids) {
                try {
                    if(faceRegion.isEmpty()||viewRect.isEmpty()){
                        return null;
                    }
                    Bitmap srcBitmap= BitmapFactory.decodeByteArray(jpeg,0,jpeg.length);
                    Matrix matrix=new Matrix();
                    //计算图片上的剪裁区域
                    matrix.postScale(srcBitmap.getWidth()/viewRect.width(),srcBitmap.getHeight()/viewRect.height());
                    RectF imgFaceRegion=new RectF(0,0,0,0);
                    matrix.mapRect(imgFaceRegion,faceRegion);
                    //剪裁区域缩放
                    matrix.reset();
                    matrix.postScale(faceRegion.width()/imgFaceRegion.width(),faceRegion.height()/imgFaceRegion.height());
                    matrix.postRotate(degrees);
                    Bitmap newBitmap=Bitmap.createBitmap(srcBitmap,(int)imgFaceRegion.left,(int)imgFaceRegion.top,(int)imgFaceRegion.width(),(int)imgFaceRegion.height(),matrix,false);
                    srcBitmap.recycle();
                    ByteArrayOutputStream out = new ByteArrayOutputStream();
                    newBitmap.compress(Bitmap.CompressFormat.JPEG,80,out);
                    newBitmap.recycle();
                    out.close();
                    return out.toByteArray();
                } catch (Exception e) {
                    Log.e(TAG,"保存文件失败",e);
                    return null;
                }
            }
            @Override
            protected void onPostExecute(byte[] jpeg) {
                super.onPostExecute(jpeg);
                this.progressDialog.dismiss();
                if(jpeg==null){
                    mCameraWrap.startPreview(false);
                    Toast.makeText(getContext(), "拍照失败", Toast.LENGTH_LONG).show();
                    startPreview();
                    return;
                }
                if (mListener != null) {
                    mListener.onFaceCaptured(jpeg);
                }
            }
        };
        task.execute();
    }
    /**
     * 功能一：SurfaceView初始化及回调
     * */
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        try {
            mCameraWrap.open(getContext(),cameraId);
            mCameraWrap.setPreviewDisplay(holder);
            mCameraWrap.setAdapterSize(holder.getSurfaceFrame());
            startPreview();
            Log.i(TAG,"surfaceCreated=>"+holder.getSurfaceFrame());
        } catch (Exception e) {
            Log.e(TAG,"surfaceCreated Error",e);
            Toast.makeText(getContext(), "摄像头初始化失败！", Toast.LENGTH_LONG).show();
        }
    }
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        try {
            stopPreview();
            mCameraWrap.setAdapterSize(holder.getSurfaceFrame());
            startPreview();
            Log.i(TAG,"surfaceChanged=>"+holder.getSurfaceFrame());
        } catch (Exception e) {
            Log.e(TAG,"surfaceChanged Error",e);
        }
    }
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        try {
            Log.i(TAG,"surfaceDestroyed=>"+holder.getSurfaceFrame());
            stopPreview();
            mCameraWrap.release();
        } catch (Exception e) {
            Log.e(TAG,"surfaceDestroyed Error",e);
        }
    }
    /**
     * 功能二：监听器-返回调用者所拍摄的图片
     * */
    public FaceCameraView setEventListener(FaceCameraView.EventListener mListener) {
        this.mListener = mListener;
        return this;
    }
    public interface EventListener {
        void onFaceCaptured(byte[] jpeg);
    }
    /**
     * 功能三：UI显示效果-遮罩
     * */
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        viewRect.set(0,0,getWidth(),getHeight());
        float radius = Math.min(viewRect.width(), viewRect.height()) * 0.8f;
        clipRect.set(0, 0, (int)radius, (int)radius);
        clipRect.offsetTo(viewRect.centerX() - clipRect.width()/2, viewRect.centerY() - clipRect.height()/ 2);
    }
    public class Sharp extends View{
        private final Path mPath = new Path();
        private final Paint mPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
        private final boolean DEBUG=false;
        public Sharp(Context context) {
            super(context);
            if(Build.VERSION.SDK_INT>=18){
                return;
            }
            super.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        }
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.save();
            mPath.reset();
            mPath.addOval(clipRect,Path.Direction.CCW);
            canvas.clipPath(mPath, Region.Op.DIFFERENCE);
            canvas.drawColor(0xFF000000);
            if(DEBUG&&!faceRegion.isEmpty()){
                canvas.clipRect(viewRect,Region.Op.UNION);
                mPaint.setStyle(Paint.Style.STROKE);
                mPaint.setColor(0xFFFF0000);
                canvas.drawRect(faceRegion,mPaint);
            }
            canvas.restore();
            postInvalidateDelayed(200);//刷新界面
        }
    }
}